package treediff.wrapper.maintenance;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.lexer.Page;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import util.nodecloner.ChildFinder;
import util.parserUnifier.ParserUnifier;
import wish.stages.ParsingStage;

public class ClusteredTreeMatching {

	public double clusteredTreeMatching(Node n1, Node n2,int siblings1, int siblings2){
		
		if (sameLabel(n1,n2)){
			
			NodeList nc1 = ChildFinder.getChildren(n1); 
			NodeList nc2 = ChildFinder.getChildren(n2);
			
			int m = nc1.size();
			int n = nc2.size();
			
			double[][] M = new double[m+1][n+1];
			
			for (int i = 0; i < M.length; i++) {
				M[i][0] = 0;
			}
			
			for (int j = 0; j < M[0].length; j++) {
				M[0][j] = 0;
			}
			
			for (int i = 1; i <= m; i++) {
				for (int j = 1; j <= n; j++) {
					M[i][j] = Math.max(M[i][j-1], Math.max(M[i-1][j], M[i-1][j-1] + clusteredTreeMatching(nc1.elementAt(i-1), nc2.elementAt(j-1),m,n)));
				}
			}
			
			double div = Math.max(siblings1, siblings2);
			
			if (m>0 && n>0){
				
				return M[m][n]*1.0/div;
				
			}else{
				
				return M[m][n]+1.0/div;
			}
			
		}
		
		return 0.0;
	}

	private boolean sameLabel(Node n1, Node n2) {
		
		if (n1 instanceof TagNode && n2 instanceof TagNode){
			
			String tag1 = ((TagNode)n1).getTagName();
			String tag2 = ((TagNode)n2).getTagName();
			
			if (tag1.equalsIgnoreCase(tag2)){
				return true;
			}
			return false;
		}else if (n1 instanceof TextNode && n2 instanceof TextNode){
			return true;
		}
		
		return false;
	}
	
	public static void main(String[] args) throws IOException, ParserException {
		
		String type = "training";
		
		System.setOut(new PrintStream(new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/Maintenance/out." + type)));
		
		File prefix = new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/Maintenance/" + type + "/");
		
		File f = new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/QueryResults/" + type);
		
		File ef = new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/QueryResultsEmpty/" + type);
		
		File[] folders = f.listFiles();
		
//		folders = new File[1];
//		
//		folders[0] = new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/QueryResults/" + type + "/1024/");
		
		BufferedWriter[] bw = new BufferedWriter[folders.length];
		
		List<Thread> threadPool = new ArrayList<Thread>();
		
		for (int i = 0; i < folders.length; i++) {
			
			String name = folders[i].getName();
			
			System.err.println("DATABASE: " + i + " - " + name);
			
			File out = new File(prefix,name);
			
			if (out.exists()){
				continue;
			}
			
			out.mkdir();
			synchronized (bw) {
				bw[i] = new BufferedWriter(new FileWriter(new File(out,"out.txt")));

			}
			
			File folder = new File(f,name);
			
			File emptyfolder = new File(ef,name);
			
			File[] files = combine(folder.listFiles(),emptyfolder.listFiles());
			
			Node[] nodes = createNodes(files);
			
			for (int j = 0; j < nodes.length; j++) {
				
				File f1 = files[j];

				Node n1 = nodes[j];
				
				for (int k = j+1; k < files.length; k++) {
					
					File f2 = files[k];
					
					Node n2 = nodes[k];
					
					threadPool.add(new ClusteredTreeMatching().executeThread(n1,n2,name,f1.getName(),f2.getName(),bw[i]));
					
				}
				
			}
			
		}
		
//		Node n1 = createNode(new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/QueryResults/training/9/0.html"));
//		
//		Node n2 = createNode(new File("/proj/dbNoBackup/pjbarrio/Experiments/Wrappers/QueryResults/training/1/1.html"));		
//		
//		ClusteredTreeMatching cl = new ClusteredTreeMatching();
//		
//		System.out.println(cl.clusteredTreeMatching(n1, n2, 1, 1));
		
		for (Thread thread : threadPool) {
			try {
				thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		for (int j = 0; j < bw.length; j++) {
			
			if (bw[j] != null)
				bw[j].close();
		}
		
	}

	private static Node[] createNodes(File[] files) throws ParserException, IOException {
		
		Node[] nodes = new Node[files.length];
		
		for (int i = 0; i < nodes.length; i++) {
			
			nodes[i] = createNode(files[i]);
			
		}
		
		return nodes;
	}

	private Thread executeThread(Node n1, Node n2, String name, String file1, String file2, BufferedWriter bw) {
		
		Thread t1 = new Thread(new ClusteredTreeMatchingRunnable(n1,n2,name,file1,file2,bw));
		
		t1.start();
				
		return t1;
	}

	private synchronized static File[] combine(File[] files1, File[] files2) {
		
		File[] ret = new File[files1.length + files2.length];
		
		for (int i = 0; i < files1.length; i++) {
			
			ret[i]=files1[i];
			
		}
		
		for (int i = 0; i < files2.length; i++) {
			
			ret[files1.length + i] = files2[i];
			
		}
		
		return ret;
	}

	private synchronized static Node createNode(File file) throws IOException, ParserException {
		
		String htmlContent = ParsingStage.readFile(file);
		
		Parser parser = new Parser(new Lexer(new Page(htmlContent, "UTF-8")));
		
		return ParserUnifier.unify(parser,"root");
		
	}
	
}
